package com.winner.data.exception.handler;

import java.util.List;
import java.util.stream.Collectors;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.alibaba.excel.exception.ExcelAnalysisException;
import com.winner.data.exception.BusinessEnum;
import com.winner.data.exception.BusinessException;
import com.winner.data.exception.R;

import lombok.extern.slf4j.Slf4j;

/**
 * 全局异常处理类(当抛出自定义异常后,可以给前端返错误码) stores return result in local before immediately returning it 不要写2行
 *
 * @author wangxinle5
 * @since 2022-09-20
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public R unknownExceptionHandle(final Exception exception) {
        log.error("other exception is", exception);
        return R.error(exception.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
    public R businessException(final BusinessException exception) {
        return R.error(exception.getExceptionEnum(), exception.getObject());
    }

    @ExceptionHandler(ExcelAnalysisException.class)
    public R businessException(final ExcelAnalysisException exception) {
        return R.error(exception.getMessage());
    }

    /**
     * 平时做数据合法性检查,通常都是这样写 if (StringUtils.isEmpty(message)) { throw new IllegalArgumentException("输入信息错误!"); }
     *
     * 可以用 spring包下的Assert 简化为一行, Assert.hasLength(id, "id字符不为null且字符长度不为0"); Assert.notNull(id,"id不能为空");
     * Assert.notEmpty(new ArrayList<>(), "集合不能为空"); 也可以使用hutool包下的Assert Assert.checkBetween(0, 1, 3);
     *
     * 最后还是最推荐使用spring的 @Validated实体类, @NotBlank, @Pattern(regexp = "男|女", message = "性别必须是男或女")正则来校验参数最方便,
     * 当然对一些需要写代码自行判断的 使用hutool的Validator.isEmail("51940196@qq.com"), 可以抛出自定义异常/也可return R.fail("入参错误")
     *
     * @param exception
     * @return 结果
     */
    @ExceptionHandler(value = {IllegalArgumentException.class})
    public R illegalArgumentException(final IllegalArgumentException exception) {
        return R.error(BusinessEnum.REQUEST_FIELD_ERROR, exception.getMessage());
    }

    /**
     * 对多个字段进行sping注解校验
     *
     * @param exception
     * @return 结果
     */
    @ExceptionHandler(value = {ValidationException.class})
    public R constraintViolationException(final ConstraintViolationException exception) {
        List<String> list = exception.getConstraintViolations().stream().map(ConstraintViolation::getMessage)
            .collect(Collectors.toList());
        return R.error(BusinessEnum.REQUEST_FIELD_ERROR, list);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException exception,
        final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
        List<ObjectError> errorsObj = exception.getBindingResult().getAllErrors();
        List<String> errors =
            errorsObj.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.toList());
        R errorResponse = R.error(BusinessEnum.REQUEST_FIELD_ERROR, errors);
        return handleExceptionInternal(exception, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(
        final HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        R errorResponse = R.error(BusinessEnum.REQUEST_METHOD_NOT_SUPPORT);
        return handleExceptionInternal(ex, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex,
        final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
        R errorResponse = R.error(BusinessEnum.INVALIDATE_JSON_FORMAT);
        return handleExceptionInternal(ex, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }
}
